package com.itcast.security.service.impl;

import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.itcast.common.constant.Jzo2oApiConstants;
import com.itcast.common.model.dto.request.LoginReqDTO;
import com.itcast.common.model.dto.request.MemberLoginReqDTO;
import com.itcast.common.model.dto.request.WechatLoginReqDTO;
import com.itcast.common.model.dto.response.LoginResDTO;
import com.itcast.common.properties.ApplicationProperties;
import com.itcast.common.utils.RestTemplateUtils;
import com.itcast.security.model.Member;
import com.itcast.security.model.User;
import com.itcast.security.service.ILoginService;
import com.itcast.security.service.IMemberService;
import com.itcast.security.service.IUserService;
import com.jzo2o.api.publics.dto.response.BooleanResDTO;
import com.jzo2o.common.constants.UserType;
import com.jzo2o.common.enums.SmsBussinessTypeEnum;
import com.jzo2o.common.expcetions.BadRequestException;
import com.jzo2o.common.expcetions.RequestForbiddenException;
import com.jzo2o.common.utils.JwtTool;
import com.jzo2o.thirdparty.core.wechat.WechatService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

/**
 * @author itcast
 */
@Service
public class LoginServiceImpl implements ILoginService {
    @Resource
    private IUserService userService;
    @Resource
    private JwtTool jwtTool;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private IMemberService memberService;
    @Resource
    private WechatService wechatService;
    @Resource
    private RestTemplateUtils restTemplateUtils;
    @Resource
    private ApplicationProperties applicationProperties;

    /**
     * 管理员登录
     *
     * @param loginReqDTO 管理员登录请求模型
     * @return token
     */
    @Override
    public LoginResDTO adminLogin(LoginReqDTO loginReqDTO) {
        User user = userService.findByUsername(loginReqDTO.getUsername());
        if (user == null) {
            throw new RequestForbiddenException("账号或密码错误，请重新输入");
        }
        // 比对密码
        if (!passwordEncoder.matches(loginReqDTO.getPassword(), user.getPassword())) {
            throw new RequestForbiddenException("账号或密码错误，请重新输入");
        }

        String token = jwtTool.createToken(user.getId(), user.getName(), user.getAvatar(), UserType.OPERATION);

        LoginResDTO loginResDTO = new LoginResDTO();
        loginResDTO.setToken(token);
        loginResDTO.setNickname(user.getName());
        return loginResDTO;
    }

    /**
     * 发送登录验证码
     *
     * @param phone 手机号
     */
    @Override
    public void sendCode(String phone) {
        //封装请求参数
        Map<String, String> requestBody = new HashMap<>();
        requestBody.put("phone", phone);
        requestBody.put("bussinessType", String.valueOf(SmsBussinessTypeEnum.SERVE_STAFF_LOGIN.getType()));

        //构建请求url
        String url = applicationProperties.getJzo2oPublicsHost() + Jzo2oApiConstants.SEND_SMS_CODE;

        //发起http请求
        restTemplateUtils.post(url, requestBody);
    }

    /**
     * 普通用户登录
     *
     * @param memberLoginReqDTO 普通用户登录请求模型
     * @return token
     */
    @Override
    public LoginResDTO memberLogin(MemberLoginReqDTO memberLoginReqDTO) {
        // 校验验证码是否为空
        if (CharSequenceUtil.isBlank(memberLoginReqDTO.getVerifyCode())) {
            throw new BadRequestException("手机号码或短信验证码错误");
        }

        // 校验验证码是否正确
        //家政项目中，验证码业务类型是枚举类，固定死的，这里我们借用 SmsBussinessTypeEnum.SERVE_STAFF_LOGIN 类型
        String url = CharSequenceUtil.format(applicationProperties.getJzo2oPublicsHost() + Jzo2oApiConstants.SMS_VERIFY, memberLoginReqDTO.getPhone(), memberLoginReqDTO.getVerifyCode());
        BooleanResDTO booleanResDTO = JSONUtil.toBean(restTemplateUtils.get(url), BooleanResDTO.class);
        boolean verifyResult = booleanResDTO.getIsSuccess();
        if (!verifyResult) {
            throw new BadRequestException("手机号码或短信验证码错误");
        }

        // 登录校验，根据手机查询普通用户信息
        Member member = memberService.findByPhone(memberLoginReqDTO.getPhone());

        // 自动注册
        if (member == null) {
            member = memberService.add(null, memberLoginReqDTO.getPhone());
        }

        // 生成登录token
        String token = jwtTool.createToken(member.getId(), member.getNickname(), member.getAvatar(), UserType.C_USER);

        LoginResDTO loginResDTO = new LoginResDTO();
        loginResDTO.setToken(token);
        loginResDTO.setNickname(member.getNickname());
        return loginResDTO;
    }

    /**
     * 普通用户微信登录
     *
     * @param wechatLoginReqDTO 微信登录请求模型
     * @return 登录token
     */
    @Override
    public LoginResDTO wechatLogin(WechatLoginReqDTO wechatLoginReqDTO) {
        //1.调用微信api,根据code获取openId
        String openId = wechatService.getOpenid(wechatLoginReqDTO.getCode());

        //2.根据openId查询用户
        Member member = memberService.getByOpenid(openId);

        //3.如果用户为空，则新增
        if (ObjectUtil.isEmpty(member)) {
            //3.1调用微信api获取用户绑定的手机号
            String phone = wechatService.getPhone(wechatLoginReqDTO.getPhoneCode());

            //3.2根据手机号查询用户
            member = memberService.findByPhone(phone);
            if (ObjectUtil.isEmpty(member)) {
                //如果未查询到用户，说明是新用户，新增用户
                member = memberService.add(openId, phone);
            } else {
                //如果查询到用户，说明是老用户，更新openId
                memberService.fillOpenid(member.getId(), openId);
            }
        }

        // 4.生成登录token
        String token = jwtTool.createToken(member.getId(), member.getNickname(), member.getAvatar(), UserType.C_USER);

        LoginResDTO loginResDTO = new LoginResDTO();
        loginResDTO.setToken(token);
        loginResDTO.setNickname(member.getNickname());
        return loginResDTO;
    }
}
